﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Text;
using SOM.AbstractDAL;
using SOM.Model;
using SOM.SingletonContext;
using System.Linq.Expressions;

namespace SOM.ConcreteDAL
{
    public class ReclamacaoDAL : AbstractReclamacaoDAL
    {
        private SOMEntities _contexto;

        public ReclamacaoDAL()
        {
            _contexto = new SOMEntities();
        }

        /// <summary>
        /// Retorna todas as reclamacoes
        /// </summary>
        /// <returns></returns>
        public override List<Reclamacao> ReturnAll()
        {
            var consulta = from r in _contexto.ReclamacoesSet.Include("img_imagem").Include("img_imagem.mti_metadado_imagem").Include("vdo_video")
                    .Include("vdo_video.mtv_metadado_video").Include("loc_localizacao").Include("ins_instituicao").Include("com_comentario").Include("usr_usuario")
                           select r;

            return consulta.ToList();
        }

        /// <summary>
        /// Retorna uma reclamação pelo seu ID
        /// </summary>
        /// <param name="idReclamcao"></param>
        /// <returns></returns>
        public override Reclamacao FindById(int idReclamacao)
        {
            var consulta =
                from r in
                    _contexto.ReclamacoesSet.Include("img_imagem").Include("img_imagem.mti_metadado_imagem").Include("vdo_video")
                    .Include("vdo_video.mtv_metadado_video").Include("loc_localizacao").Include("ins_instituicao").Include("com_comentario").Include("usr_usuario")
                where r.rec_id_reclamacao.Equals(idReclamacao)
                select r;

            return consulta.Count() == 0 ? null : consulta.First();
        }

        /// <summary>
        /// Carrega uma reclamação no contexto atual.
        /// </summary>
        /// <param name="idReclamacao"></param>
        /// <param name="contexto"></param>
        /// <returns></returns>
        public override Reclamacao Load(int idReclamacao, SOMEntities contexto)
        {
            var consulta =
                from r in
                    contexto.ReclamacoesSet.Include("img_imagem").Include("img_imagem.mti_metadado_imagem").Include("vdo_video")
                    .Include("vdo_video.mtv_metadado_video").Include("loc_localizacao").Include("ins_instituicao").Include("com_comentario")
                where r.rec_id_reclamacao.Equals(idReclamacao)
                select r;

            return consulta.Count() == 0 ? null : consulta.First();
        }

        /// <summary>
        /// Retorna as reclamações ordenadas por data de submissão.
        /// </summary>
        /// <param name="quantidade">Número de reclamações que serão retornadas</param>
        /// <returns></returns>
        public override List<Reclamacao> GetTopReclamacoes(int quantidade)
        {
            using (SOMEntities contexto = new SOMEntities())
            {

                var consulta =
                    from r in
                        contexto.ReclamacoesSet.Include("vdo_video").Include("img_imagem").Include("tag").Include(
                        "ins_instituicao").Include("loc_localizacao").Include("usr_usuario")
                    where r.rec_id_status != 4 //Não pode ser reprovada.
                    orderby r.rec_dt_data descending
                    select r;

                return consulta.Take(quantidade).ToList();
            }
        }

        public override void Insert(Reclamacao reclamacao)
        {
            _contexto.AddToReclamacoesSet(reclamacao);
        }

        /// <summary>
        /// Insere uma reclamação.
        /// </summary>
        /// <param name="reclamacao"></param>
        public override void Insert(Reclamacao reclamacao, SOMEntities contexto)
        {
            contexto.AddToReclamacoesSet(reclamacao);
            contexto.SaveChanges();
        }

        /// <summary>
        /// Atualiza uma reclamação
        /// </summary>
        /// <param name="reclamacao"></param>
        public override void Update(Reclamacao reclamacao)
        {
            _contexto.Attach(reclamacao);
            _contexto.SaveChanges();
        }

        /// <summary>
        /// Atualiza uma reclamação.
        /// </summary>
        /// <param name="reclamacao"></param>
        /// <param name="contexto"></param>
        public override void Update(Reclamacao reclamacao, SOMEntities contexto)
        {
            contexto.Refresh(RefreshMode.ClientWins,reclamacao);
            contexto.SaveChanges();
        }

        /// <summary>
        /// Remove uma reclamação
        /// </summary>
        /// <param name="reclamacao"></param>
        public override void Delete(Reclamacao reclamacao)
        {
            _contexto.DeleteObject(reclamacao);

            _contexto.SaveChanges();
        }

        public override void Delete(Reclamacao reclamacao, SOMEntities contexto)
        {
            contexto.DeleteObject(reclamacao);
            contexto.SaveChanges();
        }

        /// <summary>
        /// Retorna as reclamações que satisfaçam uma certa condição
        /// </summary>
        /// <param name="predicate">Condição de busca</param>
        /// <returns>Lista de reclamações</returns>
        public override List<Reclamacao> FindByPredicate(Expression<Func<Reclamacao,bool>> predicate)
        {
            using(SOMEntities contexto = new SOMEntities())
            {
                var consulta =
                    from reclamacao in
                        contexto.ReclamacoesSet.Include("vdo_video").Include("img_imagem").Include("tag").Include
                        ("ins_instituicao").Include("loc_localizacao")
                    where contexto.ReclamacoesSet.Any(predicate)
                    select reclamacao;

                return consulta.Count() == 0 ? null : consulta.ToList();
            }
        }

        /// <summary>
        /// Retorna reclamações de um usuário
        /// </summary>
        /// <param name="nickname"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByNickname(string nickname)
        {
            var consulta =
                from r in
                    _contexto.ReclamacoesSet.Include("vdo_video").Include("img_imagem").Include("tag").Include(
                    "ins_instituicao").Include("loc_localizacao")
                where r.usr_usuario.usr_ds_nickname.Equals(nickname)
                select r;

            return consulta.ToList();
        }

        /// <summary>
        /// Busca por reclamações que correspondem as palavras chaves passadas como parâmetro.
        /// </summary>
        /// <param name="palavrasChave"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByPalavraChave(string palavraChave)
        {
            using (SOMEntities contexto = new SOMEntities())
            {
                var consulta =
                    from rec in
                        contexto.ReclamacoesSet.Include("ins_instituicao").Include("img_imagem").Include("vdo_video").
                        Include("loc_localizacao").Include("usr_usuario")
                    where rec.tag.Any(tag => tag.tag_ds_tag.Equals(palavraChave))
                    select rec;

                return consulta.Count() == 0 ? null : consulta.ToList();
            }
        }

        /// <summary>
        /// Pesquisa por palavra chave e usuário
        /// </summary>
        /// <param name="palavraChave"></param>
        /// <param name="nickname"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByPalavraChave(string palavraChave, string nickname)
        {
            var consulta = from rec in _contexto.ReclamacoesSet.Include("ins_instituicao").Include("img_imagem").Include("vdo_video").Include("loc_localizacao")
                           where rec.usr_usuario.usr_ds_nickname.Equals(nickname) &&
                                 rec.tag.Any(tag => tag.tag_ds_tag.Equals(palavraChave))
                           select rec;



            return consulta.Count() == 0 ? null : consulta.ToList();
        }

        /// <summary>
        /// Retorna as reclamações de um usuário por palavra chave.
        /// </summary>
        /// <param name="descricao"></param>
        /// <param name="nickName"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByUsuarioDescricao(string descricao, string nickName)
        {
            if (!string.IsNullOrEmpty(descricao))
            {
                var consultaDescricao = from rec in _contexto.ReclamacoesSet.
                                            Include("ins_instituicao").Include("tag").Include("loc_localizacao").Include("img_imagem").Include("vdo_video")
                                        where rec.rec_ds_reclamacao.Contains(descricao) &&
                                              rec.usr_usuario.usr_ds_nickname.Equals(nickName)
                                        select rec;
                return consultaDescricao.Count() == 0 ? null : consultaDescricao.ToList();
            }
            return null;
        }

        /// <summary>
        /// Retorna uma lista de reclamações de uma instituição.
        /// </summary>
        /// <param name="cnpj"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByInstituicao(string cnpj)
        {
            using (SOMEntities contexto = new SOMEntities())
            {
                var consultaDescricao = from rec in _contexto.ReclamacoesSet.
                                             Include("ins_instituicao").Include("tag").Include("loc_localizacao").Include("img_imagem").Include("vdo_video").Include("usr_usuario")
                                        where rec.ins_instituicao.ins_nu_cnpj.Equals(cnpj)
                                        select rec;
                return consultaDescricao.Count() == 0 ? null : consultaDescricao.ToList();
            }
        }

        /// <summary>
        /// Retorna uma lista de reclamações através de uma descrição
        /// </summary>
        /// <param name="descricaoReclamacao"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByDescricao(string descricaoReclamacao)
        {
            using (SOMEntities contexto = new SOMEntities())
            {
                var consulta = from rec in contexto.ReclamacoesSet.Include("ins_instituicao").Include("tag").Include("loc_localizacao").Include("img_imagem").Include("vdo_video").Include("usr_usuario")
                               where rec.rec_ds_reclamacao.Contains(descricaoReclamacao)
                               select rec;

                return consulta.ToList();
            }
        }

        /// <summary>
        /// Busca uma reclamação por sua data de publicação
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public override List<Reclamacao> FindByData(DateTime dataInicial, DateTime dataFinal)
        {
            using(SOMEntities contexto = new SOMEntities())
            {
                var consulta =
                    from rec in
                        contexto.ReclamacoesSet.Include("ins_instituicao").Include("tag").Include("loc_localizacao").
                        Include("img_imagem").Include("vdo_video").Include("usr_usuario")
                    where rec.rec_dt_data >= dataInicial && rec.rec_dt_data <= dataFinal
                    select rec;

                return consulta.Count() == 0 ? null : consulta.ToList();
            }
        }

        public override List<Reclamacao> FindByDataDescricao(DateTime dataInicial, DateTime dataFinal, string descricao)
        {
            using(SOMEntities contexto = new SOMEntities())
            {
                var consulta =
                    from rec in
                        contexto.ReclamacoesSet.Include("ins_instituicao").Include("tag").Include("loc_localizacao").
                        Include("img_imagem").Include("vdo_video").Include("usr_usuario")
                    where rec.rec_dt_data >= dataInicial && rec.rec_dt_data < dataFinal
                    select rec;

                if(!string.IsNullOrEmpty(descricao))
                {
                    consulta = consulta.Where(rec => rec.rec_ds_reclamacao.Contains(descricao));
                }

                return consulta.ToList();
            }
        }

        /// <summary>
        /// Envia as modificações para o banco de dados.
        /// </summary>
        public override void SaveChanges()
        {
            _contexto.SaveChanges();
        }
    }
}
